package com.ybt.router.core.routertable.manager;

import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Observable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import org.apache.log4j.Logger;

import com.ybt.router.core.routertable.IAddress;
import com.ybt.router.core.routertable.IServiceRouter;

public class RouterContainer extends Observable {
    private Logger logger = Logger.getLogger(RouterContainer.class);
    private Map<String, IServiceRouter> serviceConfig;
    private ReentrantReadWriteLock routerLock;
    private Lock readLock;
    private Lock writeLock;
    private static RouterContainer config;

    private RouterContainer() {
        serviceConfig=new ConcurrentHashMap<String, IServiceRouter>();
        routerLock = new ReentrantReadWriteLock();
        readLock = routerLock.readLock();
        writeLock = routerLock.writeLock();
    }

    public static RouterContainer getInstance() {
        if (config == null) {
            synchronized (RouterContainer.class) {
                if (config == null) {
                    config = new RouterContainer();
                }
            }
        }
        return config;
    }

    public boolean updateRouter(String serviceName, IServiceRouter router) {
        router.setServiceName(serviceName);
        return updateRouter(router);
    }

    public boolean updateRouter(IServiceRouter router) {
        try {
            writeLock.lock();
            RouterChange change = new RouterChange();
            IServiceRouter old = null;
            if ((old = serviceConfig.get(router.getServiceName())) != null) {
                change.setChangeMethod(RouterChange.CHANGE_UPDATE);
                logger.debug("update service router:\n" + router);
            } else {
                change.setChangeMethod(RouterChange.CHANGE_ADD);
                logger.debug("add service router:\n" + router);
            }
            change.setOldRouter(old);
            serviceConfig.put(router.getServiceName(), router);
            this.notifyObservers(change);
        } finally {
            writeLock.unlock();
        }
        return true;
    }

    public boolean deleteRouter(IServiceRouter router) {
        try {
            writeLock.lock();
            RouterChange change = new RouterChange();
            IServiceRouter old = null;
            if ((old = serviceConfig.remove(router.getServiceName())) != null) {
                change.setChangeMethod(RouterChange.CHANGE_DELETE);
                logger.debug("delete service router:\n" + old);
                change.setOldRouter(old);
                this.notifyObservers(change);
            } else {
                logger.debug("no service router:\n" + router);
            }

        } finally {
            writeLock.unlock();
        }
        return true;
    }

    public IServiceRouter getRouter(String serviceName) {
        try {
            readLock.lock();
            IServiceRouter router = serviceConfig.get(serviceName);
            if (router != null) {
                return (IServiceRouter) router.clone();
            }
        } catch (Exception e) {
            logger.debug("", e);
        } finally {
            readLock.unlock();
        }
        return null;
    }

    public Hashtable<String, IAddress> getAllSenderIAddress() {
        try {
            readLock.lock();
            Hashtable<String, IAddress> result = new Hashtable<String, IAddress>();
            Iterator<String> it = this.serviceConfig.keySet().iterator();
            while (it.hasNext()) {
                IServiceRouter router = serviceConfig.get(it.next());
                String key = router.getOutAddress().getAddressKey();
                if (!result.containsKey(key)) {
                    result.put(key, (IAddress) router.getOutAddress().clone());
                }
            }
            return result;
        } catch (Exception e) {
            logger.debug("", e);
        } finally {
            readLock.unlock();
        }
        return null;
    }
    
    public IAddress getSenderIAddress(String addresskey) {
        try {
            readLock.lock();
            IAddress result = null;
            Iterator<String> it = this.serviceConfig.keySet().iterator();
            while (it.hasNext()) {
                IServiceRouter router = serviceConfig.get(it.next());
                String key = router.getOutAddress().getAddressKey();
                if (addresskey.equals(key)) {
                    if(result == null){
                        result=(IAddress) router.getOutAddress().clone();
                    }
                }
            }
            return result;
        } catch (Exception e) {
            logger.debug("", e);
        } finally {
            readLock.unlock();
        }
        return null;
    }

    public Hashtable<String, IAddress> getAllReceverIAddress() {
        try {
            readLock.lock();
            Hashtable<String, IAddress> result = new Hashtable<String, IAddress>();
            Iterator<String> it = this.serviceConfig.keySet().iterator();
            while (it.hasNext()) {
                IServiceRouter router = serviceConfig.get(it.next());
                result.put(router.getServiceName(), (IAddress) router
                        .getInAddress().clone());
            }
            return result;
        } catch (Exception e) {
            logger.debug("", e);
        } finally {
            readLock.unlock();
        }
        return null;
    }

    
    public void readLock() {
        readLock.lock();
    }
    public void unReadLock() {
        readLock.unlock();
    }
    
    public void writeLock() {
        writeLock.lock();
    }
    public void unWriteLock() {
        writeLock.unlock();
    }

}
